import { Metadata_Key } from "../../constants";
import { BreakOrContext, MethodAroundAdvice } from '../common';
import { AdviceType, Aspect } from './aspect';
import { TransactionalMetadata, TransactionalOption } from "./transactional";
import { Scope } from "../ioc";

/** js引擎运行时的Transactional支持(由Java实现) */
interface JsTransactionSupport {
  /**
   * 在必要时创建事务
   * @param transactionName 事务名称
   * @param txOption        创建事务时的配置项
   * @returns               事务信息用于提交、回滚事务
   */
  createTransactionIfNecessary(transactionName: string, txOption: TransactionalOption): TransactionInfo;

  /**
   * 处理一个throwable，完成事务。我们可以提交或回滚，这取决于配置。
   * @param txInfo 事务信息 {@link #createTransactionIfNecessary(Value, Value)}
   * @param ex     异常对象
   */
  completeTransactionAfterThrowing(txInfo: TransactionInfo, ex: any): void;

  /**
   * 在方法成功执行完成调用后调用，用于提交事务
   * @param txInfo 事务信息 {@link #createTransactionIfNecessary(Value, Value)}
   */
  commitTransactionAfterReturning(txInfo: TransactionInfo): void;

  /**
   * 清除 TransactionInfo ThreadLocal (防止内存泄漏)
   */
  cleanupTransactionInfo(txInfo: TransactionInfo): void;
}

/** 事务信息(Java类型) */
interface TransactionInfo {
}

/** js引擎运行时的Transactional支持(由Java实现) */
declare let jsTransactionSupport: JsTransactionSupport;

// 模拟jsTransactionSupport对象
// let jsTransactionSupport!: JsTransactionSupport;
// if (!jsTransactionSupport) {
//   jsTransactionSupport = <JsTransactionSupport>{
//     createTransactionIfNecessary: function (transactionName: string, txOption: TransactionalOption) {
//     },
//     completeTransactionAfterThrowing: function (txInfo: TransactionInfo, ex: any) {
//     },
//     commitTransactionAfterReturning: function (txInfo: TransactionInfo) {
//     },
//     cleanupTransactionInfo: function (txInfo: TransactionInfo) {
//     },
//   };
// }

/** Transactional 事务增强实现 */
@Aspect({type: AdviceType.MethodAroundAdvice, scope: Scope.Singleton})
export class TransactionalAdvice implements MethodAroundAdvice {
  order: number = Number.MAX_VALUE;

  filterPointcut(target: any, property: PropertyKey, argsOrValue?: any): boolean {
    const metadata: TransactionalMetadata = Reflect.getMetadata(Metadata_Key.transactional, target, <string>property);
    // console.log("metadata --> ", property, " | metadata=", TransactionalOption.is(metadata));
    return TransactionalOption.is(metadata);
  }

  before(target: any, method: PropertyKey, args: any[]): BreakOrContext {
    const context: BreakOrContext = {isReturn: false};
    const metadata: TransactionalMetadata = Reflect.getMetadata(Metadata_Key.transactional, target, <string>method);
    if (!TransactionalOption.is(metadata)) {
      return context;
    }
    // 生成随机的事务名称
    // console.log("--------->>> before | ", metadata.transactionName, " | metadata=", TransactionalOption.is(metadata))
    const txInfo = jsTransactionSupport.createTransactionIfNecessary(metadata.transactionName, metadata);
    context.context = {txInfo};
    return context;
  }

  after(target: any, method: PropertyKey, args: any[], successful: boolean, returnValue?: any, error?: any, aroundContext?: any): void {
    // console.log("<<<--------- after  | ", method, " | aroundContext=", aroundContext, "\n");
    const txInfo = <TransactionInfo>aroundContext.txInfo;
    try {
      if (successful) {
        // 提交事务
        jsTransactionSupport.commitTransactionAfterReturning(txInfo);
      } else {
        // 处理一个throwable，完成事务。我们可以提交或回滚，这取决于配置
        jsTransactionSupport.completeTransactionAfterThrowing(txInfo, error);
      }
    } finally {
      // 清除 TransactionInfo ThreadLocal (防止内存泄漏)
      jsTransactionSupport.cleanupTransactionInfo(txInfo);
    }
  }
}
